/*
 * 动态线程池（oneThread）基础组件项目
 *
 * 版权所有 (C) [2024-至今] [山东流年网络科技有限公司]
 *
 * 保留所有权利。
 *
 * 1. 定义和解释
 *    本文件（包括其任何修改、更新和衍生内容）是由[山东流年网络科技有限公司]及相关人员开发的。
 *    "软件"指的是与本文件相关的任何代码、脚本、文档和相关的资源。
 *
 * 2. 使用许可
 *    本软件的使用、分发和解释均受中华人民共和国法律的管辖。只有在遵守以下条件的前提下，才允许使用和分发本软件：
 *    a. 未经[山东流年网络科技有限公司]的明确书面许可，不得对本软件进行修改、复制、分发、出售或出租。
 *    b. 任何未授权的复制、分发或修改都将被视为侵犯[山东流年网络科技有限公司]的知识产权。
 *
 * 3. 免责声明
 *    本软件按"原样"提供，没有任何明示或暗示的保证，包括但不限于适销性、特定用途的适用性和非侵权性的保证。
 *    在任何情况下，[山东流年网络科技有限公司]均不对任何直接、间接、偶然、特殊、典型或间接的损害（包括但不限于采购替代商品或服务；使用、数据或利润损失）承担责任。
 *
 * 4. 侵权通知与处理
 *    a. 如果[山东流年网络科技有限公司]发现或收到第三方通知，表明存在可能侵犯其知识产权的行为，公司将采取必要的措施以保护其权利。
 *    b. 对于任何涉嫌侵犯知识产权的行为，[山东流年网络科技有限公司]可能要求侵权方立即停止侵权行为，并采取补救措施，包括但不限于删除侵权内容、停止侵权产品的分发等。
 *    c. 如果侵权行为持续存在或未能得到妥善解决，[山东流年网络科技有限公司]保留采取进一步法律行动的权利，包括但不限于发出警告信、提起民事诉讼或刑事诉讼。
 *
 * 5. 其他条款
 *    a. [山东流年网络科技有限公司]保留随时修改这些条款的权利。
 *    b. 如果您不同意这些条款，请勿使用本软件。
 *
 * 未经[山东流年网络科技有限公司]的明确书面许可，不得使用此文件的任何部分。
 *
 * 本软件受到[山东流年网络科技有限公司]及其许可人的版权保护。
 */

package com.nageoffer.onethread.web.starter.core.executor;

import com.nageoffer.onethread.core.constant.Constants;
import com.nageoffer.onethread.web.starter.core.WebContainerEnum;
import com.nageoffer.onethread.web.starter.core.WebThreadPoolBaseMetrics;
import com.nageoffer.onethread.web.starter.core.WebThreadPoolConfig;
import com.nageoffer.onethread.web.starter.core.WebThreadPoolState;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServer;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

/**
 * Tomcat 线程池接口
 */
@Slf4j
public class TomcatWebThreadPoolService extends AbstractWebThreadPoolService {

    @Override
    protected Executor getExecutor(WebServer webServer) {
        return ((TomcatWebServer) webServer).getTomcat().getConnector().getProtocolHandler().getExecutor();
    }

    @Override
    public void updateThreadPool(WebThreadPoolConfig config) {
        try {
            ThreadPoolExecutor tomcatExecutor = (ThreadPoolExecutor) executor;
            int originalCorePoolSize = tomcatExecutor.getCorePoolSize();
            int originalMaximumPoolSize = tomcatExecutor.getMaximumPoolSize();
            long originalKeepAliveTime = tomcatExecutor.getKeepAliveTime(TimeUnit.SECONDS);

            if (config.getCorePoolSize() > originalMaximumPoolSize) {
                tomcatExecutor.setMaximumPoolSize(config.getMaximumPoolSize());
                tomcatExecutor.setCorePoolSize(config.getCorePoolSize());
            } else {
                tomcatExecutor.setCorePoolSize(config.getCorePoolSize());
                tomcatExecutor.setMaximumPoolSize(config.getMaximumPoolSize());
            }
            tomcatExecutor.setKeepAliveTime(config.getKeepAliveTime(), TimeUnit.SECONDS);

            log.info("[Tomcat] Changed web thread pool. corePoolSize: {}, maximumPoolSize: {}, keepAliveTime: {}",
                    String.format(Constants.CHANGE_DELIMITER, originalCorePoolSize, config.getCorePoolSize()),
                    String.format(Constants.CHANGE_DELIMITER, originalMaximumPoolSize, config.getMaximumPoolSize()),
                    String.format(Constants.CHANGE_DELIMITER, originalKeepAliveTime, config.getKeepAliveTime()));
        } catch (Exception ex) {
            log.error("Failed to modify the Tomcat thread pool parameter.", ex);
        }
    }

    @Override
    public WebThreadPoolBaseMetrics getBasicMetrics() {
        ThreadPoolExecutor tomcatExecutor = (ThreadPoolExecutor) executor;
        int corePoolSize = tomcatExecutor.getCorePoolSize();
        int maximumPoolSize = tomcatExecutor.getMaximumPoolSize();
        long keepAliveTime = tomcatExecutor.getKeepAliveTime(TimeUnit.SECONDS);

        BlockingQueue<?> blockingQueue = tomcatExecutor.getQueue();
        int blockingQueueSize = blockingQueue.size();
        int remainingCapacity = blockingQueue.remainingCapacity();
        int queueCapacity = blockingQueueSize + remainingCapacity;
        String rejectedExecutionHandlerName = tomcatExecutor.getRejectedExecutionHandler().getClass().getSimpleName();

        return WebThreadPoolBaseMetrics.builder()
                .corePoolSize(corePoolSize)
                .maximumPoolSize(maximumPoolSize)
                .keepAliveTime(keepAliveTime)
                .workQueueName(blockingQueue.getClass().getSimpleName())
                .workQueueSize(blockingQueueSize)
                .workQueueRemainingCapacity(remainingCapacity)
                .workQueueCapacity(queueCapacity)
                .rejectedHandlerName(rejectedExecutionHandlerName)
                .build();
    }

    @Override
    public WebThreadPoolState getRuntimeState() {
        ThreadPoolExecutor tomcatExecutor = (ThreadPoolExecutor) executor;
        int corePoolSize = tomcatExecutor.getCorePoolSize();
        int maximumPoolSize = tomcatExecutor.getMaximumPoolSize();
        int activeCount = tomcatExecutor.getActiveCount();
        long completedTaskCount = tomcatExecutor.getCompletedTaskCount();
        int largestPoolSize = tomcatExecutor.getLargestPoolSize();
        int currentPoolSize = tomcatExecutor.getPoolSize();
        long keepAliveTime = tomcatExecutor.getKeepAliveTime(TimeUnit.SECONDS);

        BlockingQueue<?> blockingQueue = tomcatExecutor.getQueue();
        int blockingQueueSize = blockingQueue.size();
        int remainingCapacity = blockingQueue.remainingCapacity();
        int queueCapacity = blockingQueueSize + remainingCapacity;
        String rejectedExecutionHandlerName = tomcatExecutor.getRejectedExecutionHandler().getClass().getSimpleName();
        return WebThreadPoolState.builder()
                .corePoolSize(corePoolSize)
                .maximumPoolSize(maximumPoolSize)
                .activePoolSize(activeCount)
                .completedTaskCount(completedTaskCount)
                .largestPoolSize(largestPoolSize)
                .currentPoolSize(currentPoolSize)
                .keepAliveTime(keepAliveTime)
                .workQueueName(blockingQueue.getClass().getSimpleName())
                .workQueueSize(blockingQueueSize)
                .workQueueRemainingCapacity(remainingCapacity)
                .workQueueCapacity(queueCapacity)
                .rejectedHandlerName(rejectedExecutionHandlerName)
                .build();
    }

    @Override
    public WebContainerEnum getWebContainerType() {
        return WebContainerEnum.TOMCAT;
    }
}
